Aula 3 - Preparação de Dados

Escola de Métodos em Ciência Política

Frederico Bertholini

tidyverse

Manifesto tidyverse

O tidyverse, também chamado por muitos de hadleyverse, é um conjunto de pacotes que, por compartilharem esses princípios do manifesto tidy, podem ser utilizados naturalmente em conjunto. Pode-se dizer que existe o R antes do tidyverse e o R depois do tidyverse.

Os princípios fundamentais do tidyverse são:

  • Reutilizar estruturas de dados existentes.

  • Organizar funções simples usando o pipe.

  • Aderir à programação funcional.

  • Projetado para ser usado por seres humanos.

Manifesto tidy

Usando o pipe - O operador %>%

O operador %>% (pipe) foi uma das grandes revoluções recentes do R, tornando a leitura de códigos mais lógica, fácil e compreensível.

library(tidyverse)
library(magrittr)

Ceci n’est pas un pipe

Ideia

A ideia do operador %>% (pipe) é bem simples: usar o valor resultante da expressão do lado esquerdo como primeiro argumento da função do lado direito.

  • As duas linhas abaixo são equivalentes.
f(x, y)
x %>% f(y)

E se aumentarmos o código?

Vamos calcular a raiz quadrada da soma dos valores de 1 a 4.

Primeiro, sem o pipe.

sqrt(sum(x))
[1] 3.162278

Agora com o pipe.

x %>% 
  sum %>% 
  sqrt
[1] 3.162278

E se realmente tivermos muitas funções aninhadas?

A utilização do pipe transforma um código confuso e difícil de ser lido em algo simples e intuitivo.

Receita de bolo - sem pipe

Tente entender o que é preciso fazer.

esfrie(
  asse(
    coloque(
      bata(
        acrescente(
          recipiente(rep("farinha", 2), "água", 
                     "fermento", "leite", "óleo"), 
          "farinha", até = "macio"), 
        duração = "3min"), 
      lugar = "forma", tipo = "grande", 
      untada = TRUE), duração = "50min"), 
  "geladeira", "20min")

Receita de bolo - com pipe

Desistiu? Agora veja como fica escrevendo com o %>%:

recipiente(rep("farinha", 2), "água", "fermento", "leite", "óleo") %>%
  acrescente("farinha", até = "macio") %>%
  bata(duração = "3min") %>%
  coloque(lugar = "forma", tipo = "grande", untada = TRUE) %>%
  asse(duração = "50min") %>%
  esfrie("geladeira", "20min")

Importação no tidyverse

Importação com readr, readxl, haven e DBI

No tidyverse, geralmente

  • Funções read_<formato> servem para ler um arquivo no formato <formato>
  • Funções write_<formato> servem para escrever num arquivo com o formato <formato>

Arquivos de texto

  • csv, tsv, txt, …

  • Para esses aqui, usar o pacote readr

  • Você também pode experimentar o data.table::fread

Arquivos binários

  • .RData, .rds, .feather, .fst

  • .dta (Stata), .sas7bdat (SAS), .sav (SPSS)

  • Ler com readr, haven, feather, fst.

Bancos de dados

  • MySQL, SQL Server, PostgreSQL, SQLite, …

  • Spark, MongoDB, Hive, …

  • Utilizar pacotes DBI e odbc

Tidy data e janitor

Veremos mais à frente, mas janitor::clean_names() é uma ferramenta tidy

library(janitor)

Pacotes dplyr e tidyr

Conjunto de dados

Vamos trabalhar com a base decisoes, que contém decisões do Tribunal de Justiça de São Paulo

decisoes <- read_rds("dados/decisoes.rds")
glimpse(decisoes)
Rows: 11,731
Columns: 9
$ `ID Decisão`     <chr> "11094999", "11093733", "11093677", "11093270", "1109…
$ n_processo       <chr> "0057003-20.2017.8.26.0000", "0052762-03.2017.8.26.00…
$ `Classe/Assunto` <chr> "Habeas Corpus / Homicídio Simples", "Habeas Corpus /…
$ Município        <chr> "Cosmópolis", "São Paulo", "Ribeirão Preto", "Araçatu…
$ Câmara           <chr> "3ª Câmara de Direito Criminal", "3ª Câmara de Direit…
$ `Data decisão`   <chr> "19/12/2017", "19/12/2017", "19/12/2017", "14/12/2017…
$ `Data registro`  <chr> "19/12/2017", "19/12/2017", "19/12/2017", "19/12/2017…
$ Juiz             <chr> "Luiz Antonio Cardoso", "Luiz Antonio Cardoso", "Luiz…
$ `txt decisão`    <chr> NA, NA, NA, "Execução Penal –  Comutação de Penas –  …
decisoes <- read_rds("dados/decisoes.rds") %>%
  janitor::clean_names() # com dois pontos eu não preciso usar library
glimpse(decisoes)
Rows: 11,731
Columns: 9
$ id_decisao     <chr> "11094999", "11093733", "11093677", "11093270", "110933…
$ n_processo     <chr> "0057003-20.2017.8.26.0000", "0052762-03.2017.8.26.0000…
$ classe_assunto <chr> "Habeas Corpus / Homicídio Simples", "Habeas Corpus / R…
$ municipio      <chr> "Cosmópolis", "São Paulo", "Ribeirão Preto", "Araçatuba…
$ camara         <chr> "3ª Câmara de Direito Criminal", "3ª Câmara de Direito …
$ data_decisao   <chr> "19/12/2017", "19/12/2017", "19/12/2017", "14/12/2017",…
$ data_registro  <chr> "19/12/2017", "19/12/2017", "19/12/2017", "19/12/2017",…
$ juiz           <chr> "Luiz Antonio Cardoso", "Luiz Antonio Cardoso", "Luiz A…
$ txt_decisao    <chr> NA, NA, NA, "Execução Penal –  Comutação de Penas –  De…

Características do dplyr

  • A utilização é facilitada com o emprego do operador %>%

  • No primeiro argumento colocamos o data.frame ou o tibble, e nos outros argumentos colocamos o que queremos fazer.

As cinco funções principais do dplyr

  • select: selecionar colunas

  • filter: filtrar linhas

  • mutate: criar colunas

  • summarise: sumarizar colunas

  • arrange: ordenar linhas

select

select

  • Utilizar starts_with(x), contains(x), matches(x), one_of(x), etc.
  • Possível colocar nomes, índices, e intervalos de variáveis com :.

select em ação 1

decisoes %>% 
  select(id_decisao, n_processo, municipio, juiz)
# A tibble: 11,731 × 4
   id_decisao n_processo                municipio           juiz                
   <chr>      <chr>                     <chr>               <chr>               
 1 11094999   0057003-20.2017.8.26.0000 Cosmópolis          Luiz Antonio Cardoso
 2 11093733   0052762-03.2017.8.26.0000 São Paulo           Luiz Antonio Cardoso
 3 11093677   0055169-79.2017.8.26.0000 Ribeirão Preto      Luiz Antonio Cardoso
 4 11093270   9000580-82.2017.8.26.0032 Araçatuba           Grassi Neto         
 5 11093374   0052938-79.2017.8.26.0000 São Paulo           Grassi Neto         
 6 11093320   9000723-79.2017.8.26.0482 Presidente Prudente Grassi Neto         
 7 11091506   0003276-86.2015.8.26.0075 Bertioga            Grassi Neto         
 8 11093326   9000298-11.2017.8.26.0625 Taubaté             Grassi Neto         
 9 11092475   0004653-39.2015.8.26.0028 Aparecida           Grassi Neto         
10 11093773   2221930-66.2017.8.26.0000 Jandira             Luiz Antonio Cardoso
# ℹ 11,721 more rows

select em ação 2

decisoes %>% 
  select(classe_assunto:id_decisao, juiz)
# A tibble: 11,731 × 4
   classe_assunto                                    n_processo id_decisao juiz 
   <chr>                                             <chr>      <chr>      <chr>
 1 Habeas Corpus / Homicídio Simples                 0057003-2… 11094999   Luiz…
 2 Habeas Corpus / Roubo                             0052762-0… 11093733   Luiz…
 3 Habeas Corpus / DIREITO PENAL                     0055169-7… 11093677   Luiz…
 4 Agravo de Execução Penal / Pena Privativa de Lib… 9000580-8… 11093270   Gras…
 5 Mandado de Segurança / Crimes do Sistema Naciona… 0052938-7… 11093374   Gras…
 6 Agravo de Execução Penal / Pena Privativa de Lib… 9000723-7… 11093320   Gras…
 7 Apelação / Tráfico de Drogas e Condutas Afins     0003276-8… 11091506   Gras…
 8 Agravo de Execução Penal / Livramento Condicional 9000298-1… 11093326   Gras…
 9 Apelação / Tráfico de Drogas e Condutas Afins     0004653-3… 11092475   Gras…
10 Habeas Corpus / Furto Qualificado                 2221930-6… 11093773   Luiz…
# ℹ 11,721 more rows

select em ação 3

decisoes %>% 
  select(id_decisao, starts_with('data_'))
# A tibble: 11,731 × 3
   id_decisao data_decisao data_registro
   <chr>      <chr>        <chr>        
 1 11094999   19/12/2017   19/12/2017   
 2 11093733   19/12/2017   19/12/2017   
 3 11093677   19/12/2017   19/12/2017   
 4 11093270   14/12/2017   19/12/2017   
 5 11093374   14/12/2017   19/12/2017   
 6 11093320   14/12/2017   19/12/2017   
 7 11091506   14/12/2017   19/12/2017   
 8 11093326   14/12/2017   19/12/2017   
 9 11092475   14/12/2017   19/12/2017   
10 11093773   19/12/2017   19/12/2017   
# ℹ 11,721 more rows

Operações com select 1

  • selecione as colunas que acabam com “cisao”.
decisoes %>% 
  select(ends_with("cisao"))
# A tibble: 11,731 × 3
   id_decisao data_decisao txt_decisao                                          
   <chr>      <chr>        <chr>                                                
 1 11094999   19/12/2017    <NA>                                                
 2 11093733   19/12/2017    <NA>                                                
 3 11093677   19/12/2017    <NA>                                                
 4 11093270   14/12/2017   "Execução Penal –  Comutação de Penas –  Decreto n. …
 5 11093374   14/12/2017   "Mandado de segurança – Impetração por agente despro…
 6 11093320   14/12/2017   "Execução Penal – Apuração de falta grave em procedi…
 7 11091506   14/12/2017   "Tráfico de entorpecentes – Agente que traz consigo …
 8 11093326   14/12/2017   "Execução Penal – Pedido de livramento condicional d…
 9 11092475   14/12/2017   "Tráfico de entorpecentes –  Agente que tem em depós…
10 11093773   19/12/2017    <NA>                                                
# ℹ 11,721 more rows

Operações com select 2

  • tire as colunas de texto = ‘txt_decisao’ e classe/assunto = ‘classe_assunto’.
    • Dica: veja os exemplos de ?select em Drop variables ...
decisoes %>% 
  select(-classe_assunto, -txt_decisao)
# A tibble: 11,731 × 7
   id_decisao n_processo       municipio camara data_decisao data_registro juiz 
   <chr>      <chr>            <chr>     <chr>  <chr>        <chr>         <chr>
 1 11094999   0057003-20.2017… Cosmópol… 3ª Câ… 19/12/2017   19/12/2017    Luiz…
 2 11093733   0052762-03.2017… São Paulo 3ª Câ… 19/12/2017   19/12/2017    Luiz…
 3 11093677   0055169-79.2017… Ribeirão… 3ª Câ… 19/12/2017   19/12/2017    Luiz…
 4 11093270   9000580-82.2017… Araçatuba 8ª Câ… 14/12/2017   19/12/2017    Gras…
 5 11093374   0052938-79.2017… São Paulo 8ª Câ… 14/12/2017   19/12/2017    Gras…
 6 11093320   9000723-79.2017… Presiden… 8ª Câ… 14/12/2017   19/12/2017    Gras…
 7 11091506   0003276-86.2015… Bertioga  8ª Câ… 14/12/2017   19/12/2017    Gras…
 8 11093326   9000298-11.2017… Taubaté   8ª Câ… 14/12/2017   19/12/2017    Gras…
 9 11092475   0004653-39.2015… Aparecida 8ª Câ… 14/12/2017   19/12/2017    Gras…
10 11093773   2221930-66.2017… Jandira   3ª Câ… 19/12/2017   19/12/2017    Luiz…
# ℹ 11,721 more rows

filter

filter

  • Use , ou & para “e” e | para “ou”.
  • Condições separadas por vírgulas é o mesmo que separar por &.

filter em ação

decisoes %>% 
  select(n_processo, id_decisao, municipio, juiz) %>% 
  filter(municipio == 'São Paulo')
# A tibble: 2,446 × 4
   n_processo                id_decisao municipio juiz                
   <chr>                     <chr>      <chr>     <chr>               
 1 0052762-03.2017.8.26.0000 11093733   São Paulo Luiz Antonio Cardoso
 2 0052938-79.2017.8.26.0000 11093374   São Paulo Grassi Neto         
 3 2214049-38.2017.8.26.0000 11093604   São Paulo Luiz Antonio Cardoso
 4 2227499-48.2017.8.26.0000 11093642   São Paulo Luiz Antonio Cardoso
 5 9002384-31.2017.8.26.0050 11093376   São Paulo Grassi Neto         
 6 0021158-39.2015.8.26.0050 11091508   São Paulo Grassi Neto         
 7 7005375-26.2015.8.26.0198 11091668   São Paulo Grassi Neto         
 8 9002039-65.2017.8.26.0050 11094451   São Paulo Grassi Neto         
 9 2203993-43.2017.8.26.0000 11094449   São Paulo Grassi Neto         
10 0099423-21.2016.8.26.0050 11091474   São Paulo Grassi Neto         
# ℹ 2,436 more rows

Dica: usar %in%

library(lubridate) # para trabalhar com as datas
#`day(dmy(data_decisao))` pega o dia da decisão. 
decisoes %>% 
  select(id_decisao, municipio, data_decisao, juiz) %>% 
  # municipio igual a campinas ou jaú, OU dia da decisão maior ou igual a 25
  filter(municipio %in% c('Campinas', 'Jaú') & day(dmy(data_decisao)) >= 25)
# A tibble: 71 × 4
   id_decisao municipio data_decisao juiz                  
   <chr>      <chr>     <chr>        <chr>                 
 1 11093018   Jaú       28/11/2017   Ivan Sartori          
 2 11082822   Campinas  29/11/2017   João Morenghi         
 3 11082845   Campinas  29/11/2017   João Morenghi         
 4 11052266   Campinas  30/11/2017   Augusto de Siqueira   
 5 11052894   Campinas  30/11/2017   Poças Leitão          
 6 11052213   Campinas  30/11/2017   Poças Leitão          
 7 11049986   Campinas  29/11/2017   Xavier de Souza       
 8 11049760   Campinas  30/11/2017   Encinas Manfré        
 9 11044116   Campinas  30/11/2017   Encinas Manfré        
10 11043650   Campinas  30/11/2017   Fernando Torres Garcia
# ℹ 61 more rows

Mais ação

decisoes %>% 
  select(juiz) %>% 
  # filtra juízes que têm `Z` ou `z` no nome
  filter(str_detect(juiz, regex("z", ignore_case = TRUE))) %>% 
  # conta e ordena os juizes em ordem decrescente
  count(juiz, sort = TRUE) %>%
  head(5)
# A tibble: 5 × 2
  juiz                          n
  <chr>                     <int>
1 Gilberto Ferreira da Cruz   237
2 Diniz Fernando              198
3 Sérgio Mazina Martins       173
4 Luiz Antonio Cardoso        163
5 Rachid Vaz de Almeida       150

Obs

A função str_detect() retorna TRUE se um elemento do vetor de textos é compatível com uma expressão regular. Estudaremos o pacote stringr e as funções str_* em outra aula.

  • filtre apenas casos em que id_decisao não é NA
decisoes %>% 
  filter(is.na(id_decisao))
# A tibble: 65 × 9
   id_decisao n_processo classe_assunto municipio camara data_decisao
   <chr>      <chr>      <chr>          <chr>     <chr>  <chr>       
 1 <NA>       <NA>       <NA>           <NA>      <NA>   <NA>        
 2 <NA>       <NA>       <NA>           <NA>      <NA>   <NA>        
 3 <NA>       <NA>       <NA>           <NA>      <NA>   <NA>        
 4 <NA>       <NA>       <NA>           <NA>      <NA>   <NA>        
 5 <NA>       <NA>       <NA>           <NA>      <NA>   <NA>        
 6 <NA>       <NA>       <NA>           <NA>      <NA>   <NA>        
 7 <NA>       <NA>       <NA>           <NA>      <NA>   <NA>        
 8 <NA>       <NA>       <NA>           <NA>      <NA>   <NA>        
 9 <NA>       <NA>       <NA>           <NA>      <NA>   <NA>        
10 <NA>       <NA>       <NA>           <NA>      <NA>   <NA>        
# ℹ 55 more rows
# ℹ 3 more variables: data_registro <chr>, juiz <chr>, txt_decisao <chr>

  • filtre todas as decisões de 2018.

    – Dica: função lubridate::year()

decisoes %>% 
  filter(year(dmy(data_decisao)) == 2018)
# A tibble: 314 × 9
   id_decisao n_processo            classe_assunto municipio camara data_decisao
   <chr>      <chr>                 <chr>          <chr>     <chr>  <chr>       
 1 11107242   0009617-63.2016.8.26… Apelação / Ro… São Paulo 2ª Câ… 15/01/2018  
 2 11107425   2227593-93.2017.8.26… Habeas Corpus… Iepê      2ª Câ… 15/01/2018  
 3 11107492   0076977-24.2016.8.26… Embargos de D… São Paulo 2ª Câ… 15/01/2018  
 4 11107361   0012191-36.2017.8.26… Agravo de Exe… Campinas  2ª Câ… 15/01/2018  
 5 11107383   2218460-27.2017.8.26… Habeas Corpus… Sorocaba  2ª Câ… 15/01/2018  
 6 11107331   0006928-63.2017.8.26… Agravo de Exe… Sorocaba  2ª Câ… 15/01/2018  
 7 11107651   0000297-54.2017.8.26… Apelação / Tr… Junqueir… 2ª Câ… 15/01/2018  
 8 11107485   2225548-19.2017.8.26… Habeas Corpus… Nazaré P… 2ª Câ… 15/01/2018  
 9 11107335   0006934-70.2017.8.26… Agravo de Exe… Sorocaba  2ª Câ… 15/01/2018  
10 11107340   0006682-67.2017.8.26… Agravo de Exe… Sorocaba  2ª Câ… 15/01/2018  
# ℹ 304 more rows
# ℹ 3 more variables: data_registro <chr>, juiz <chr>, txt_decisao <chr>

mutate

mutate

  • Aceita várias novas colunas iterativamente.

  • Novas variáveis devem ter o mesmo length que o nrow do bd original ou 1.

mutate em ação

decisoes %>% 
  select(n_processo, data_decisao, data_registro) %>% 
  mutate(tempo = dmy(data_registro) - dmy(data_decisao))
# A tibble: 11,731 × 4
   n_processo                data_decisao data_registro tempo 
   <chr>                     <chr>        <chr>         <drtn>
 1 0057003-20.2017.8.26.0000 19/12/2017   19/12/2017    0 days
 2 0052762-03.2017.8.26.0000 19/12/2017   19/12/2017    0 days
 3 0055169-79.2017.8.26.0000 19/12/2017   19/12/2017    0 days
 4 9000580-82.2017.8.26.0032 14/12/2017   19/12/2017    5 days
 5 0052938-79.2017.8.26.0000 14/12/2017   19/12/2017    5 days
 6 9000723-79.2017.8.26.0482 14/12/2017   19/12/2017    5 days
 7 0003276-86.2015.8.26.0075 14/12/2017   19/12/2017    5 days
 8 9000298-11.2017.8.26.0625 14/12/2017   19/12/2017    5 days
 9 0004653-39.2015.8.26.0028 14/12/2017   19/12/2017    5 days
10 2221930-66.2017.8.26.0000 19/12/2017   19/12/2017    0 days
# ℹ 11,721 more rows

mutate em ação

  • Crie uma coluna binária drogas que vale TRUE se no texto da decisão algo é falado de drogas e FALSE caso contrário. – Dica: str_detect

Obs.: Considere tanto a palavra ‘droga’ como seus sinônimos, ou algum exemplo de droga e retire os casos em que txt_decisao é vazio

decisoes %>% 
  filter(!is.na(txt_decisao)) %>% # filtrando quem não é NA
  mutate(txt_decisao = tolower(txt_decisao),
         droga = str_detect(txt_decisao,
    "droga|entorpecente|psicotr[óo]pico|maconha|haxixe|coca[íi]na")
    ) %>%
  dplyr::select(n_processo,droga) 
# A tibble: 6,933 × 2
   n_processo                droga
   <chr>                     <lgl>
 1 9000580-82.2017.8.26.0032 FALSE
 2 0052938-79.2017.8.26.0000 FALSE
 3 9000723-79.2017.8.26.0482 FALSE
 4 0003276-86.2015.8.26.0075 TRUE 
 5 9000298-11.2017.8.26.0625 TRUE 
 6 0004653-39.2015.8.26.0028 TRUE 
 7 9000788-34.2017.8.26.0269 FALSE
 8 9000673-53.2017.8.26.0482 FALSE
 9 7005620-87.2017.8.26.0482 FALSE
10 7001988-32.2017.8.26.0198 FALSE
# ℹ 6,923 more rows

summarise

summarise

  • Retorna um vetor de tamanho 1 a partir de uma operação com as variáveis (aplicação de uma função).
  • Geralmente é utilizado em conjunto com group_by().
  • Algumas funções importantes: n(), n_distinct().

summarise Em ação

decisoes %>% 
  select(n_processo, municipio, data_decisao) %>%
  #        pega ano da decisão
  mutate(ano_julgamento = year(dmy(data_decisao)),
         # pega o ano do processo 0057003-20.2017.8.26.0000" -> "2017"
         ano_proc = str_sub(n_processo, 12, 15),
         # transforma o ano em inteiro
         ano_proc = as.numeric(ano_proc),
         # calcula o tempo em anos
         tempo_anos = ano_julgamento - ano_proc) %>% 
  group_by(municipio) %>% 
  summarise(n = n(),
            media_anos = mean(tempo_anos,na.rm=T),
            min_anos = min(tempo_anos,na.rm=T),
            max_anos = max(tempo_anos,na.rm=T)) 

Resultado

# A tibble: 315 × 5
   municipio               n media_anos min_anos max_anos
   <chr>               <int>      <dbl>    <dbl>    <dbl>
 1 Adamantina             17      0.765        0        5
 2 Aguaí                  19      1.16         0        2
 3 Agudos                  8      3.25         0        6
 4 Altinópolis             7      0.857        0        2
 5 Americana              56      1.41         0        9
 6 Amparo                  9      2.11         0        7
 7 Américo Brasiliense     9      1.56         0        3
 8 Andradina              41      0.707        0        5
 9 Angatuba                4      0.5          0        2
10 Aparecida              20      1.9          0        5
# ℹ 305 more rows

usando count()

A função count(), simplifica um group_by %>% summarise %>% ungroup:

decisoes %>% 
  count(juiz, sort = TRUE) %>% 
  mutate(prop = n / sum(n), 
         prop = scales::percent(prop))
# A tibble: 100 × 3
   juiz                          n prop   
   <chr>                     <int> <chr>  
 1 Gilberto Ferreira da Cruz   237 2.0203%
 2 Francisco Orlando           226 1.9265%
 3 Diniz Fernando              198 1.6878%
 4 Walter da Silva             183 1.5600%
 5 De Paula Santos             182 1.5514%
 6 Machado de Andrade          182 1.5514%
 7 Newton Neves                180 1.5344%
 8 Leme Garcia                 179 1.5259%
 9 Grassi Neto                 177 1.5088%
10 Figueiredo Gonçalves        176 1.5003%
# ℹ 90 more rows

+ fácil ainda

mas sem formato %

decisoes %>% 
  count(juiz, sort = TRUE) %>% 
  mutate(prop = prop.table(n))
# A tibble: 100 × 3
   juiz                          n   prop
   <chr>                     <int>  <dbl>
 1 Gilberto Ferreira da Cruz   237 0.0202
 2 Francisco Orlando           226 0.0193
 3 Diniz Fernando              198 0.0169
 4 Walter da Silva             183 0.0156
 5 De Paula Santos             182 0.0155
 6 Machado de Andrade          182 0.0155
 7 Newton Neves                180 0.0153
 8 Leme Garcia                 179 0.0153
 9 Grassi Neto                 177 0.0151
10 Figueiredo Gonçalves        176 0.0150
# ℹ 90 more rows

arrange

arrange

  • Simplesmente ordena de acordo com as opções.

  • Utilizar desc() para ordem decrescente ou o sinal de menos (-).

  • Quem são os cinco relatores mais prolixos?

– Dica: use str_length() – Lembre-se da função head()

arrange em ação

decisoes %>% 
  filter(!is.na(txt_decisao)) %>% 
  mutate(tamanho = str_length(txt_decisao)) %>% 
  group_by(juiz) %>% 
  summarise(n = n(), 
            tamanho_mediana = median(tamanho)) %>% 
  filter(n >= 10) %>% 
  arrange(desc(tamanho_mediana)) %>%
  head()
# A tibble: 6 × 3
  juiz                                n tamanho_mediana
  <chr>                           <int>           <dbl>
1 Airton Vieira                     154           3146.
2 Ely Amioka                         81           1847 
3 Grassi Neto                       141           1675 
4 Alcides Malossi Junior             95           1541 
5 Cesar Augusto Andrade de Castro    77           1341 
6 Juvenal Duarte                    101           1320 

tydyr

Alterando o formato de dados

Até agora, estudamos os principais ferramentas de transformação de dados do dplyr. Agora vamos aumentar nossa caixa-de-ferramentas com tidyr

  • Carregando uma nova base de dados, que completa a de decisões.
processos <- read_rds("dados/processos_nested.rds")

Fomato tidy

Funções do pacote

  • Enquanto o dplyr faz recortes na base (com filter()e select()) e adições simples (mutate(), summarise()), o tidyr mexe no formato da tabela (gather(), spread()) e faz modificações menos triviais.

  • As funções do tidyr geralmente vêm em pares com seus inversos:

    • gather() e spread(), -> substituídas por pivot_longer e pivot_wider
    • nest() e unnest(),
    • separate() e unite()

Onde estamos

https://r4ds.hadley.nz/data-transform

gather()

  • gather() empilha o banco de dados

  • pivot_longer empilha de um jeito ainda mais fácil

decisoes %>% 
  filter(!is.na(id_decisao)) %>% 
  select(id_decisao:data_registro) %>% 
  # 1. nome da coluna que vai guardar os nomes de colunas empilhadas
  # 2. nome da coluna que vai guardar os valores das colunas
  # 3. seleção das colunas a serem empilhadas
  gather(key="variavel", value="valor", -id_decisao) %>% 
  arrange(id_decisao)
# A tibble: 69,996 × 3
   id_decisao variavel       valor                                        
   <chr>      <chr>          <chr>                                        
 1 11026431   n_processo     0000009-51.2015.8.26.0546                    
 2 11026431   classe_assunto Apelação / Tráfico de Drogas e Condutas Afins
 3 11026431   municipio      Itapira                                      
 4 11026431   camara         5ª Câmara de Direito Criminal                
 5 11026431   data_decisao   30/11/2017                                   
 6 11026431   data_registro  01/12/2017                                   
 7 11026432   n_processo     0002267-69.2013.8.26.0654                    
 8 11026432   classe_assunto Apelação / Furto Qualificado                 
 9 11026432   municipio      Vargem Grande Paulista                       
10 11026432   camara         5ª Câmara de Direito Criminal                
# ℹ 69,986 more rows

pivot_longer

Base relig_income do tidyr 3 variáveis:

  • religion, nas linhas
  • income, nas colunas e
  • count, nas células
tidyr::relig_income
# A tibble: 18 × 11
   religion `<$10k` `$10-20k` `$20-30k` `$30-40k` `$40-50k` `$50-75k` `$75-100k`
   <chr>      <dbl>     <dbl>     <dbl>     <dbl>     <dbl>     <dbl>      <dbl>
 1 Agnostic      27        34        60        81        76       137        122
 2 Atheist       12        27        37        52        35        70         73
 3 Buddhist      27        21        30        34        33        58         62
 4 Catholic     418       617       732       670       638      1116        949
 5 Don’t k…      15        14        15        11        10        35         21
 6 Evangel…     575       869      1064       982       881      1486        949
 7 Hindu          1         9         7         9        11        34         47
 8 Histori…     228       244       236       238       197       223        131
 9 Jehovah…      20        27        24        24        21        30         15
10 Jewish        19        19        25        25        30        95         69
11 Mainlin…     289       495       619       655       651      1107        939
12 Mormon        29        40        48        51        56       112         85
13 Muslim         6         7         9        10         9        23         16
14 Orthodox      13        17        23        32        32        47         38
15 Other C…       9         7        11        13        13        14         18
16 Other F…      20        33        40        46        49        63         46
17 Other W…       5         2         3         4         2         7          3
18 Unaffil…     217       299       374       365       341       528        407
# ℹ 3 more variables: `$100-150k` <dbl>, `>150k` <dbl>,
#   `Don't know/refused` <dbl>

pivot_longer em ação

tidyr::relig_income %>%
  pivot_longer(!religion, 
               names_to = "income", # diz a varável onde entrarão os nomes
               values_to = "count" # diz a variável onde entrarão os valores
               )
# A tibble: 180 × 3
   religion income             count
   <chr>    <chr>              <dbl>
 1 Agnostic <$10k                 27
 2 Agnostic $10-20k               34
 3 Agnostic $20-30k               60
 4 Agnostic $30-40k               81
 5 Agnostic $40-50k               76
 6 Agnostic $50-75k              137
 7 Agnostic $75-100k             122
 8 Agnostic $100-150k            109
 9 Agnostic >150k                 84
10 Agnostic Don't know/refused    96
# ℹ 170 more rows

spread()

  • spread() espalha uma variável nas colunas e preenche com outra variável

  • Função inversa de gather

  • Bem mais fácil com pivot_wider

decisoes %>% 
  filter(!is.na(id_decisao)) %>% 
  select(id_decisao:data_registro) %>% 
  gather(key, value, -id_decisao) %>% 
  # 1. coluna a ser espalhada
  # 2. valores da coluna
  spread(key, value)
# A tibble: 11,666 × 7
   id_decisao camara         classe_assunto data_decisao data_registro municipio
   <chr>      <chr>          <chr>          <chr>        <chr>         <chr>    
 1 11026431   5ª Câmara de … Apelação / Tr… 30/11/2017   01/12/2017    Itapira  
 2 11026432   5ª Câmara de … Apelação / Fu… 30/11/2017   01/12/2017    Vargem G…
 3 11026433   5ª Câmara de … Apelação / Ro… 30/11/2017   01/12/2017    Sertãozi…
 4 11026434   12ª Câmara de… Agravo de Exe… 18/10/2017   01/12/2017    Ribeirão…
 5 11026435   15ª Câmara de… Apelação / Tr… 30/11/2017   01/12/2017    São Paulo
 6 11026442   5ª Câmara de … Apelação / Es… 30/11/2017   01/12/2017    Jales    
 7 11026445   13ª Câmara de… Apelação / Us… 30/11/2017   01/12/2017    Santa Fé…
 8 11026453   5ª Câmara de … Apelação / Cr… 30/11/2017   01/12/2017    Franca   
 9 11026455   12ª Câmara de… Apelação / Ro… 05/07/2017   01/12/2017    Franca   
10 11026456   12ª Câmara de… Apelação / Ro… 03/05/2017   01/12/2017    São José…
# ℹ 11,656 more rows
# ℹ 1 more variable: n_processo <chr>

pivot_wider

decisoes %>% 
  filter(!is.na(id_decisao)) %>% 
  select(id_decisao:data_registro) %>% 
  pivot_longer(!id_decisao, 
               names_to = "tipo", # diz a varável onde entrarão os nomes
               values_to = "info" # diz a variável onde entrarão os valores
               ) %>% 
  # 1. coluna a ser espalhada
  # 2. valores da coluna
  pivot_wider(names_from = "tipo",
              values_from = "info")
# A tibble: 11,666 × 7
   id_decisao n_processo            classe_assunto municipio camara data_decisao
   <chr>      <chr>                 <chr>          <chr>     <chr>  <chr>       
 1 11094999   0057003-20.2017.8.26… Habeas Corpus… Cosmópol… 3ª Câ… 19/12/2017  
 2 11093733   0052762-03.2017.8.26… Habeas Corpus… São Paulo 3ª Câ… 19/12/2017  
 3 11093677   0055169-79.2017.8.26… Habeas Corpus… Ribeirão… 3ª Câ… 19/12/2017  
 4 11093270   9000580-82.2017.8.26… Agravo de Exe… Araçatuba 8ª Câ… 14/12/2017  
 5 11093374   0052938-79.2017.8.26… Mandado de Se… São Paulo 8ª Câ… 14/12/2017  
 6 11093320   9000723-79.2017.8.26… Agravo de Exe… Presiden… 8ª Câ… 14/12/2017  
 7 11091506   0003276-86.2015.8.26… Apelação / Tr… Bertioga  8ª Câ… 14/12/2017  
 8 11093326   9000298-11.2017.8.26… Agravo de Exe… Taubaté   8ª Câ… 14/12/2017  
 9 11092475   0004653-39.2015.8.26… Apelação / Tr… Aparecida 8ª Câ… 14/12/2017  
10 11093773   2221930-66.2017.8.26… Habeas Corpus… Jandira   3ª Câ… 19/12/2017  
# ℹ 11,656 more rows
# ℹ 1 more variable: data_registro <chr>

  • Qual juiz julga a maior proporção de processos que tratam de drogas

– Dica: construa um data.frame contendo as colunas juiz, n_processos_drogas, n_processos_n_drogas e total_processos, remodelando os dados para haver um juiz por linha e utilizando spread()

Resolução

# A tibble: 65 × 5
# Groups:   juiz [65]
   juiz                   droga n_droga total proporcao
   <chr>                  <dbl>   <dbl> <dbl>     <dbl>
 1 Airton Vieira             23     131   154     0.149
 2 Alcides Malossi Junior    23      72    95     0.242
 3 Alexandre Almeida         41     122   163     0.252
 4 Amaro Thomé               36      96   132     0.273
 5 Andrade Sampaio           35      79   114     0.307
 6 Angélica de Almeida        2       6     8     0.25 
 7 Antonio Tadeu Ottoni       0       1     1     0    
 8 Bandeira Lins              0       2     2     0    
 9 Camargo Aranha Filho      32     109   141     0.227
10 Camilo Léllis             32     133   165     0.194
# ℹ 55 more rows

Exercício

  • Qual quantidade mensal de decisões por juiz?

  • Dica: use data_decisao dmy() e month()

Resolução

decisoes %>% 
  filter(!is.na(txt_decisao)) %>%
  mutate(txt_decisao = tolower(txt_decisao),
         droga = str_detect(txt_decisao,
    "droga|entorpecente|psicotr[óo]pico|maconha|haxixe|coca[íi]na"),
    droga=case_when(
      droga==TRUE ~ "droga",
      droga==FALSE ~ "n_droga"
    )) %>%
  group_by(juiz,droga) %>%
  summarise(n=n()) %>%
  spread(droga,n,fill = 0) %>%
  mutate(total=droga+n_droga,
         proporcao=droga/total)

Resultado

# A tibble: 65 × 5
# Groups:   juiz [65]
   juiz                   droga n_droga total proporcao
   <chr>                  <dbl>   <dbl> <dbl>     <dbl>
 1 Airton Vieira             23     131   154     0.149
 2 Alcides Malossi Junior    23      72    95     0.242
 3 Alexandre Almeida         41     122   163     0.252
 4 Amaro Thomé               36      96   132     0.273
 5 Andrade Sampaio           35      79   114     0.307
 6 Angélica de Almeida        2       6     8     0.25 
 7 Antonio Tadeu Ottoni       0       1     1     0    
 8 Bandeira Lins              0       2     2     0    
 9 Camargo Aranha Filho      32     109   141     0.227
10 Camilo Léllis             32     133   165     0.194
# ℹ 55 more rows

Exemplo para o ggplot

Unindo e separando colunas

  • unite junta duas ou mais colunas usando algum separador (_, por exemplo).
  • separate faz o inverso de unite, e uma coluna em várias usando um separador.

Exemplo de separação de colunas

  • Olhe os valores da variável classe_assunto

Exemplo de separação de colunas

  • Vamos separar a coluna classe_assunto em duas colunas

  • coluna classe e coluna assunto

  • Existe separador? -> sim, /

  • Usei count apenas em assunto

Em ação

decisoes %>% 
  select(n_processo, classe_assunto) %>% 
  separate(classe_assunto, c('classe', 'assunto'), sep = ' / ', 
           extra = 'merge', fill = 'right') %>% 
  count(assunto, sort = TRUE)

## count é um jeito resumido de usar group_by() %>% summarise(n())

Em ação

# A tibble: 152 × 2
   assunto                                n
   <chr>                              <int>
 1 Tráfico de Drogas e Condutas Afins  2441
 2 Pena Privativa de Liberdade         1106
 3 Roubo Majorado                      1093
 4 Furto Qualificado                    838
 5 Roubo                                780
 6 Progressão de Regime                 607
 7 Furto                                450
 8 Receptação                           353
 9 Homicídio Qualificado                329
10 Crimes de Trânsito                   322
# ℹ 142 more rows

List columns: nest() e unnest()

nest() e unnest() são operações inversas e servem para tratar dados complexos, como o que temos em processos

d_partes <- processos %>% 
  select(n_processo, partes) %>% 
  unnest(partes)

As list columns são uma forma condensada de guardar dados que estariam em múltiplas tabelas. Por exemplo, uma alternativa à colocar as partes numa list column seria guardar a tabela d_partes separadamente.

glimpse(d_partes)
Rows: 37,579
Columns: 5
$ n_processo <chr> "0000003-71.2016.8.26.0073", "0000003-71.2016.8.26.0073", "…
$ id         <int> 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1,…
$ name       <chr> "JOSE MARIA JUSTINO NETO", "Defensoria Pública do Estado de…
$ part       <chr> "Apelante", "Apelante", "Apelado", "Apelante", "Apelante", …
$ role       <chr> "Apelante", "Apelante", "Apelado", "Apelante", "Advogado", …

Duplicatas

Para retirar duplicatas, utilizar distinct. Ele considera apenas a primeira linha em que encontra um padrão para as combinações de variáveis escolhidas e descarta as demais.

decisoes %>% 
  distinct(municipio)
# A tibble: 315 × 1
   municipio          
   <chr>              
 1 Cosmópolis         
 2 São Paulo          
 3 Ribeirão Preto     
 4 Araçatuba          
 5 Presidente Prudente
 6 Bertioga           
 7 Taubaté            
 8 Aparecida          
 9 Jandira            
10 Flórida Paulista   
# ℹ 305 more rows

Por coluna

Para manter as demais colunas, use .keep_all=:

decisoes %>%
  distinct(municipio, camara, 
           .keep_all = TRUE)
# A tibble: 2,760 × 9
   id_decisao n_processo            classe_assunto municipio camara data_decisao
   <chr>      <chr>                 <chr>          <chr>     <chr>  <chr>       
 1 11094999   0057003-20.2017.8.26… Habeas Corpus… Cosmópol… 3ª Câ… 19/12/2017  
 2 11093733   0052762-03.2017.8.26… Habeas Corpus… São Paulo 3ª Câ… 19/12/2017  
 3 11093677   0055169-79.2017.8.26… Habeas Corpus… Ribeirão… 3ª Câ… 19/12/2017  
 4 11093270   9000580-82.2017.8.26… Agravo de Exe… Araçatuba 8ª Câ… 14/12/2017  
 5 11093374   0052938-79.2017.8.26… Mandado de Se… São Paulo 8ª Câ… 14/12/2017  
 6 11093320   9000723-79.2017.8.26… Agravo de Exe… Presiden… 8ª Câ… 14/12/2017  
 7 11091506   0003276-86.2015.8.26… Apelação / Tr… Bertioga  8ª Câ… 14/12/2017  
 8 11093326   9000298-11.2017.8.26… Agravo de Exe… Taubaté   8ª Câ… 14/12/2017  
 9 11092475   0004653-39.2015.8.26… Apelação / Tr… Aparecida 8ª Câ… 14/12/2017  
10 11093773   2221930-66.2017.8.26… Habeas Corpus… Jandira   3ª Câ… 19/12/2017  
# ℹ 2,750 more rows
# ℹ 3 more variables: data_registro <chr>, juiz <chr>, txt_decisao <chr>

janitor::get_dupes()

Use janitor::get_dupes() para averiguar os casos em que há repetição de combinações de colunas.

decisoes %>% 
  get_dupes(n_processo)
# A tibble: 114 × 10
   n_processo dupe_count id_decisao classe_assunto municipio camara data_decisao
   <chr>           <int> <chr>      <chr>          <chr>     <chr>  <chr>       
 1 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 2 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 3 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 4 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 5 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 6 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 7 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 8 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 9 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
10 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
# ℹ 104 more rows
# ℹ 3 more variables: data_registro <chr>, juiz <chr>, txt_decisao <chr>

Joins

Dados relacionais

Principais funções

Para juntar tabelas, usar inner_join, left_join, anti_join, etc.

Visualizando

Exemplo de inner join:

decisoes %>% 
  filter(data_registro == "18/01/2018", !is.na(id_decisao)) %>% 
  select(id_decisao, n_processo) %>% 
  inner_join(processos, "n_processo")

# A tibble: 169 × 5
   id_decisao n_processo                infos             partes   results 
   <chr>      <chr>                     <list>            <list>   <list>  
 1 11109089   0003779-93.2015.8.26.0597 <tibble [14 × 2]> <tibble> <tibble>
 2 11109088   3001293-25.2013.8.26.0510 <tibble [13 × 2]> <tibble> <tibble>
 3 11108246   0063566-45.2015.8.26.0050 <tibble [14 × 2]> <tibble> <tibble>
 4 11108245   0003528-84.2015.8.26.0400 <tibble [14 × 2]> <tibble> <tibble>
 5 11109087   0008470-76.2015.8.26.0072 <tibble [14 × 2]> <tibble> <tibble>
 6 11109086   0013767-62.2012.8.26.0624 <tibble [14 × 2]> <tibble> <tibble>
 7 11109085   3019561-54.2013.8.26.0405 <tibble [14 × 2]> <tibble> <tibble>
 8 11108348   0003072-91.2017.8.26.0521 <tibble [11 × 2]> <tibble> <tibble>
 9 11108725   0009578-41.2017.8.26.0050 <tibble [12 × 2]> <tibble> <tibble>
10 11108347   3001116-52.2013.8.26.0028 <tibble [12 × 2]> <tibble> <tibble>
# ℹ 159 more rows

Exemplo de right join:

decisoes %>% 
  filter(data_registro == "18/01/2018", !is.na(id_decisao)) %>% 
  select(id_decisao, n_processo) %>% 
  right_join(processos, "n_processo")

# A tibble: 11,638 × 5
   id_decisao n_processo                infos             partes   results 
   <chr>      <chr>                     <list>            <list>   <list>  
 1 11109089   0003779-93.2015.8.26.0597 <tibble [14 × 2]> <tibble> <tibble>
 2 11109088   3001293-25.2013.8.26.0510 <tibble [13 × 2]> <tibble> <tibble>
 3 11108246   0063566-45.2015.8.26.0050 <tibble [14 × 2]> <tibble> <tibble>
 4 11108245   0003528-84.2015.8.26.0400 <tibble [14 × 2]> <tibble> <tibble>
 5 11109087   0008470-76.2015.8.26.0072 <tibble [14 × 2]> <tibble> <tibble>
 6 11109086   0013767-62.2012.8.26.0624 <tibble [14 × 2]> <tibble> <tibble>
 7 11109085   3019561-54.2013.8.26.0405 <tibble [14 × 2]> <tibble> <tibble>
 8 11108348   0003072-91.2017.8.26.0521 <tibble [11 × 2]> <tibble> <tibble>
 9 11108725   0009578-41.2017.8.26.0050 <tibble [12 × 2]> <tibble> <tibble>
10 11108347   3001116-52.2013.8.26.0028 <tibble [12 × 2]> <tibble> <tibble>
# ℹ 11,628 more rows

Limpeza

Duplicatas

Para retirar duplicatas, utilizar distinct. Ele considera apenas a primeira linha em que encontra um padrão para as combinações de variáveis escolhidas e descarta as demais.

decisoes %>% 
  distinct(municipio)

# A tibble: 315 × 1
   municipio          
   <chr>              
 1 Cosmópolis         
 2 São Paulo          
 3 Ribeirão Preto     
 4 Araçatuba          
 5 Presidente Prudente
 6 Bertioga           
 7 Taubaté            
 8 Aparecida          
 9 Jandira            
10 Flórida Paulista   
# ℹ 305 more rows

Por coluna

Para manter as demais colunas, use .keep_all=:

decisoes %>%
  distinct(municipio, camara, 
           .keep_all = TRUE)

# A tibble: 2,760 × 9
   id_decisao n_processo            classe_assunto municipio camara data_decisao
   <chr>      <chr>                 <chr>          <chr>     <chr>  <chr>       
 1 11094999   0057003-20.2017.8.26… Habeas Corpus… Cosmópol… 3ª Câ… 19/12/2017  
 2 11093733   0052762-03.2017.8.26… Habeas Corpus… São Paulo 3ª Câ… 19/12/2017  
 3 11093677   0055169-79.2017.8.26… Habeas Corpus… Ribeirão… 3ª Câ… 19/12/2017  
 4 11093270   9000580-82.2017.8.26… Agravo de Exe… Araçatuba 8ª Câ… 14/12/2017  
 5 11093374   0052938-79.2017.8.26… Mandado de Se… São Paulo 8ª Câ… 14/12/2017  
 6 11093320   9000723-79.2017.8.26… Agravo de Exe… Presiden… 8ª Câ… 14/12/2017  
 7 11091506   0003276-86.2015.8.26… Apelação / Tr… Bertioga  8ª Câ… 14/12/2017  
 8 11093326   9000298-11.2017.8.26… Agravo de Exe… Taubaté   8ª Câ… 14/12/2017  
 9 11092475   0004653-39.2015.8.26… Apelação / Tr… Aparecida 8ª Câ… 14/12/2017  
10 11093773   2221930-66.2017.8.26… Habeas Corpus… Jandira   3ª Câ… 19/12/2017  
# ℹ 2,750 more rows
# ℹ 3 more variables: data_registro <chr>, juiz <chr>, txt_decisao <chr>

janitor::get_dupes()

Use janitor::get_dupes() para averiguar os casos em que há repetição de combinações de colunas.

decisoes %>% 
  get_dupes(n_processo)

janitor::get_dupes() em ação

# A tibble: 114 × 10
   n_processo dupe_count id_decisao classe_assunto municipio camara data_decisao
   <chr>           <int> <chr>      <chr>          <chr>     <chr>  <chr>       
 1 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 2 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 3 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 4 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 5 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 6 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 7 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 8 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
 9 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
10 <NA>               65 <NA>       <NA>           <NA>      <NA>   <NA>        
# ℹ 104 more rows
# ℹ 3 more variables: data_registro <chr>, juiz <chr>, txt_decisao <chr>

Exemplos janitor